#pragma once
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <iostream>
#include <memory>
#include <unordered_map>
#include <mutex>
#include <cstring>
#include<google/protobuf/map.h>
namespace mymq
{
    struct MsgQueue
    {
        using Ptr = std::shared_ptr<MsgQueue>;
        std::string name;
        bool durable;   // 是否持久化存储
        bool exclusive; // 是否独占，当一个消费者独占该队列消息后，其他消费者不能消费
        bool auto_delete;
        google::protobuf::Map<std::string, std::string> args;
        MsgQueue(){}
        MsgQueue(const std::string &qname,
                 const bool qdurable,
                 const bool qexclusive,
                 const bool qauto_delete,
                 const google::protobuf::Map<std::string, std::string> qargs)
            : name(qname), durable(qdurable), exclusive(qexclusive),
              auto_delete(qauto_delete), args(qargs)
        {
        }
        // 将其他参数里面的kv值转化为特定形式的字符串 ---> key=value&key=value....
        std::string GetArgs()
        {
            std::string result;
            for (auto start = args.begin(); start != args.end(); ++start)
            {
                result += start->first + "=" + start->second + "&";
            }
            return result;
        }
        // 将特定字符串转化为map内的kv值
        void SetArgs(std::string str_args)
        {
            std::string key;
            std::string value;
            std::vector<std::string> result;
            StrHelper::split(str_args, "&", result);
            for (auto &str : result)
            {
                size_t pos = str.find("=");
                key = str.substr(0, pos);
                value = str.substr(pos + 1);
                args[key]=value;
            }
        }
    };
    using MsgQueueMap = std::unordered_map<std::string, MsgQueue::Ptr>;
    class MsgQueueMapper
    {
    public:
        MsgQueueMapper(const std::string &dbfile) : _sql_helper(dbfile)
        {
            std::string path = FileHelper::parentderectory(dbfile);
            FileHelper::createderectory(path);
            assert(_sql_helper.Open());
            CreateTable();
        }
        void CreateTable()
        {
            //"create table if not exists queue_table(name varchar(32) primary key,durable int,exclusive int,auto_delete int,args varchar(128));"
            std::stringstream sql;
            sql << "create table if not exists queue_table(";
            sql << "name varchar(32) primary key,";
            sql << "durable int,";
            sql << "exclusive int,";
            sql << "auto_delete int,";
            sql << "args varchar(128));";
            assert(_sql_helper.Exec(sql.str(), nullptr, nullptr));
        }
        void RemoveTable()
        {
            #define DROP_TABLE_INQUE "drop table if exists queue_table"
            _sql_helper.Exec(DROP_TABLE_INQUE, nullptr, nullptr);
        }
        bool Insert(MsgQueue::Ptr &queue)
        {
            std::stringstream sql;
            sql << "insert into queue_table values(";
            sql << "'" << queue->name << "',";
            sql << "'" << queue->durable << "',";
            sql << "'" << queue->exclusive << "',";
            sql << "'" << queue->auto_delete << "',";
            sql << "'" << queue->GetArgs() << "');";
            bool ret = _sql_helper.Exec(sql.str(), nullptr, nullptr);
            if (ret == false)
            {
                //ELOG("插入数据失败%s ", sql.str().c_str());
                return false;
            }
            return true;
        }
        void Remove(const std::string &name)
        {
            std::stringstream sql;
            sql << "delete from queue_table where name=";
            sql << "'" << name << "';";
            bool ret = _sql_helper.Exec(sql.str(), nullptr, nullptr);
            if (ret == false)
            {
                ELOG("删除队列%s失败", name.c_str());
                return;
            }
        }
        // 查询在数据库中的队列信息，然后保存在MsgQueueMap中
        MsgQueueMap Recovery()
        {
            MsgQueueMap result;
            std::string sql = "select * from queue_table;";
            bool ret = _sql_helper.Exec(sql, SelectCallBack, &result);
            if(ret ==false)
            {
                ELOG("加载数据失败");
                return MsgQueueMap();
            }
            return result;
        }

    private:
        static int SelectCallBack(void *arg, int numcol, char **row, char **fields)
        {
            MsgQueueMap *result = static_cast<MsgQueueMap*>(arg);
            MsgQueue::Ptr que = std::make_shared<MsgQueue>();
            que->name = row[0];
            que->durable = (bool)std::stoi(row[1]);
            que->exclusive = (bool)std::stoi(row[2]);
            que->auto_delete = (bool)std::stoi(row[3]);
            if (row[4])
                que->SetArgs(row[4]);
            result->insert(std::make_pair(que->name, que));
            return 0;
        }

    private:
        SqliteHelper _sql_helper;
    };
    using QueueMap = std::unordered_map<std::string, MsgQueue::Ptr>;
    class MsgQueueManager
    {
    public:
        using Ptr = std::shared_ptr<MsgQueueManager>;
        MsgQueueManager(const std::string &dbfile) : _mapper(dbfile)
        {
            // 1.还原数据
            _queues = _mapper.Recovery();
        }
        // 声明消息队列
        bool DeclareQueue(const std::string &name,
                          const bool durable,
                          const bool exclusive,
                          const bool auto_delete,
                          const google::protobuf::Map<std::string, std::string> &args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto pos = _queues.find(name);
            if(pos!=_queues.end())
            {
                //DLOG("该消息队列已经存在 %s",name.c_str());
                return true;
            }
            auto que = std::make_shared<MsgQueue>(name,durable,exclusive,auto_delete,args);
            if(durable==true)
            {
                //需要永久存储
               bool ret = _mapper.Insert(que);
               if(ret ==false)
               {
                    return false;
               }
            }
            _queues.insert(std::make_pair(name,que));
            return true;
        }
        //删除指定队列
        void DeleteMsgQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it == _queues.end())
            {
                // 不存在就跳过
                return;
            }
            if (it->second->durable == true)
                _mapper.Remove(name); // 如果是持久化保存的就去数据库删除
            _queues.erase(name);
        }
        // 获取指定消息队列
        MsgQueue::Ptr SelectQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it == _queues.end())
            {
                return MsgQueue::Ptr();
            }
            return it->second;
        }
        QueueMap AllQueues()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _queues;
        }
        // 判断该消息队列是否存在
        bool Exists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it == _queues.end())
            {
                return false;
            }
            return true;
        }
        // 销毁所有消息队列
        void Clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.RemoveTable();
            _queues.clear();
        }
        size_t size() { return _queues.size(); }
    private:
        std::mutex _mutex;
        MsgQueueMapper _mapper;
        QueueMap _queues;
    };
}